/**
 * @file sb3 parser
 * @see mysb3
 */

/** @class - sb3 parser */
function mysb3() {
	if (typeof this === "function") {
		throw new Error("Please use new mysb3()");
	}

	/** @member {string} - Name of this project */
	this.name = null;

	/** @member {object} - Content of project.json */
	this.project = null;

	/** @member {string[]} - List of filename of assets */
	this.assets = [];

	/** @member {JSZip} - The JSZip object */
	this.zip = null;
}

/** Load a sb3 project from a input[type=file]
 * @param {Element} file
 * @async
 * @return {mysb3} this
 */
mysb3.prototype.loadFile = function (file) {
	return new Promise(yes => {
			var reader = new FileReader();
			//console.log("reader");
			reader.addEventListener('loadend', () => {
				yes(reader.result);
			});
			reader.readAsBinaryString(file);
		})
		.then(result => { // Use arrow function to preserve reference of "this".
			return this.loadData(result, file.name);
		});
};

/** Load a sb3 project from a blob, Uint8Array, string, etc.
 * @param {(Uint8Array|Blob|string)} data
 * @param {string} name - name of the project
 * @async
 * @return {mysb3} this
 */
mysb3.prototype.loadData = function (data, name) {
	return JSZip.loadAsync(data)
		.then(zip => {
			this.zip = zip;
			this.name = name;
			let proj = zip.file("project.json");
			if (proj === null) {
				return Promise.reject(new Error("project.json not found"));
			} else {
				return proj.async("string");
			}
		})
		.then(project => {
			try {
				this.project = JSON.parse(project);
				this.assets = [];
				this.zip.forEach(path => {
					this.assets.push(path);
				});
				return this;
			} catch (e) {
				return Promise.reject(e);
			}
		});
};

/** Call JSZip.generateAsync to get Data
 * @async
 * @param {string} [type] - return which type
 *  (base64|uint8Array|binarystring|array|blob)
 * @param {object} [options] - tell compress progress
 * @param {number} [options.cplevel=6] - compress level
 * @param {function(number)} [options.progress] - show compression progress
 * @return {(string|binaryString|Array|Blob|uint8Array)}
 */
mysb3.prototype.saveData = function (type, options) {
	return this.zip.generateAsync({
		type: type,
		compression: "DEFLATE",
		compressionOptions: {
			level: options.cplevel === undefined ? 6 : options.cplevel
		}
	}, tell => {
		if (typeof options.progress === "function") {
			options.progress(tell.percent);
		}
	});
};

/** Download file.
 * @async
 * @param {number} [cplevel=6] - compress level
 * @param {function(number)} [progress] - tell compress progress
 * @return {binarystring}
 */
mysb3.prototype.saveFile = function (cplevel, progress) {
	this.zip.file("project.json", JSON.stringify(this.project));
	return this.saveData("base64", {
			cplevel: cplevel,
			progress: progress
		})
		.then(data => {
			let a = document.createElement("a");
			a.href = "data:application/x-octet-stream;base64," + data;
			a.download = this.name;
			a.click();
			a.remove();
		});
};
